//
// reqengine - reqengine source code.
//
// $Rev$
// $Author$
// $Date$
//
// Define class Request.
//

#include "reqengine/request.h"
#include "reqengine/request_content.h"
#include "reqengine/response_content.h"

namespace reqengine {

void Request::Recycle() {
  this->id_ = 0;
  this->parent_id_ = 0;
  this->nonresponse_num_ = 0;
  this->connection_ = NULL;
  if(this->request_) {
    RequestEngine::GetInstance()->RecycleRequestContent(this->request_);
    this->request_ = NULL;
  }
  if(this->response_) {
    RequestEngine::GetInstance()->RecycleResponseContent(this->response_);
    this->response_ = NULL;
  }
  SubRequestMap::iterator iterator = this->sub_requests_.begin();
  for(; iterator != this->sub_requests_.end(); ++iterator) {
    iterator->second->Recycle();
  }
  this->sub_requests_.clear();
  RequestEngine::GetInstance()->RecycleRequest(this);
}

void Request::Divide() {
  this->request_.RequireDivide();
  size_t size = this->request_.DivideSize();
  assert(size < core::kuint32max);
  for(size_t pos = 0; pos < size; ++size) {
    RequestContent *content = this->request_.Divide(pos);
    assert(content);
    Request *request = RequestEngine::GetInstance()->CreateRequest();
    assert(request);
    this->sub_requests_.insert(std::make_pair(request->GetID(), request))
    request->SetParentID(this->GetID());
  }
}

void Request::Requesting() {
  SubRequestMap::iterator iterator = this->sub_requests_.begin();
  for(; iterator != this->sub_requests_.end(); ++iterator) {
    this->Increase();
    iterator->second->Divide();
    iterator->Requesting();
  }

  this->Map();
}

void Request::Map() {
  this->request_content->Request(this);
}

void Request::Responsing(ResponseContent *content) {
  assert(request_);
  this->response_ = content;
  if(this->parent_id_ != 0) {
    Request *request = RequestEngine::GetInstance()->GetRequest(this->parent_id_);
    if(request && request->CheckIsChild(this->GetID())) {
      request->Reduce();
    } else {
      this->Recycle();
    }
  }

  this->request_content->Response(this);
}

void Request::Reduce() {
  bool finished = false;
  {
    AutoMutex auto_mutex(&this->mutex_);
    this->Decrease();
    if(this->CheckFinishResponse()) {
      finished = true;
    }
  }
  if(finished) {
    ResponseContent *response = this->request_->CreateResponse();
    SubRequestMap::iterator iterator = this->sub_requests_.begin();
    for(; iterator != this->sub_requests_.end(); ++iterator) {
      response->Merge(iterator->second->GetResponse());
    }
    this->Responsing(response);
  }
}

}  // namespace reqengine

